﻿using System.IO;
using System.ComponentModel;
using System.Text;
using System.Runtime.InteropServices;
using System.Reflection;
using System;
using System.Collections.Generic;

namespace DevToolkit
{
    class IniFile
    {
        ///////////////////////////////////////////////////////////////////////////////////////
        //  Data Members
        ///////////////////////////////////////////////////////////////////////////////////////
        string Path;
        
        ///////////////////////////////////////////////////////////////////////////////////////
        //  Extracting functions from the kernal32.dll file
        ///////////////////////////////////////////////////////////////////////////////////////
        [DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
        static extern bool WritePrivateProfileString(string Section, string Key, string Value, string FilePath);

        [DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
        static extern uint GetPrivateProfileString(string Section, string Key, string Default, StringBuilder ReturnVal, uint Size, string FilePath);

        ///////////////////////////////////////////////////////////////////////////////////////
        //  Function:   Constructor
        //
        //  Params:     iniPath - the path to the file to read, write, modify, and configure
        //
        //  Notes:      Its going to calculate the path and get the fileInfo for it.
        ///////////////////////////////////////////////////////////////////////////////////////
        public IniFile(string IniPath)
        {
            Path = new FileInfo(IniPath).FullName.ToString();
        }
        
        ///////////////////////////////////////////////////////////////////////////////////////
        //  Function:   ReadValue
        //
        //  Params:     key - which key to be read
        //              section - which section the key is under
        //
        //  Notes:      Its going to calculate the path and get the fileInfo for it.
        ///////////////////////////////////////////////////////////////////////////////////////
        public string ReadValue(string Key, string Section)
        {
            StringBuilder value = new StringBuilder(1024);
            GetPrivateProfileString(Section, Key, "", value, (uint)value.Capacity, Path);
            return value.ToString();
        }

        ///////////////////////////////////////////////////////////////////////////////////////
        //  Function:   WriteValue
        //
        //  Params:     key - which key to be written under
        //              value - the value to be written into the key
        //              section - which section the key is under
        //
        //  Notes:      Its going to calculate the path and get the fileInfo for it.
        ///////////////////////////////////////////////////////////////////////////////////////
        public void WriteValue(string Key, string Value, string Section)
        {
            if (WritePrivateProfileString(Section, Key, Value, Path) == false)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }
        }

        ///////////////////////////////////////////////////////////////////////////////////////
        //  Function:   DeleteKey
        //
        //  Params:     key - which key to delete
        //              section - which section the key is under
        //
        //  Notes:      Its going to calculate the path and get the fileInfo for it.
        ///////////////////////////////////////////////////////////////////////////////////////
        public void DeleteKey(string Key, string Section)
        {
            WriteValue(Key, null, Section);
        }

        ///////////////////////////////////////////////////////////////////////////////////////
        //  Function:   DeleteSection
        //
        //  Params:     section - which section and all sub keys to delete
        //
        //  Notes:      Its going to calculate the path and get the fileInfo for it.
        ///////////////////////////////////////////////////////////////////////////////////////
        public void DeleteSection(string Section)
        {
            WriteValue(null, null, Section);
        }

        ///////////////////////////////////////////////////////////////////////////////////////
        //  Function:   KeyExists
        //
        //  Params:     key - the string to look for on the left side of the "="
        //              section - its the section header to look under for the key
        //
        //  Notes:      Its going to calculate the path and get the fileInfo for it.
        ///////////////////////////////////////////////////////////////////////////////////////
        public bool KeyExists(string Key, string Section)
        {
            // This will not work if the key is in the file but the value is empty
            //return ReadValue(Key, Section).Length > 0;

            List<string> text = new List<string>();
            foreach (string str in File.ReadAllLines(Path))
                text.Add(str);

            foreach (string line in text)
            {
                string[] pair = line.Split('=');

                if (pair[0] == Key)
                    return true;
            }
            return false;
        }

        ///////////////////////////////////////////////////////////////////////////////////////
        //  Function:   SectionExists
        //
        //  Params:     Section - section to find
        //
        //  Notes:      Its going to check if the section exists.
        ///////////////////////////////////////////////////////////////////////////////////////
        public bool SectionExists(string Section)
        {
            List<string> text = new List<string>();
            foreach (string str in File.ReadAllLines(Path))
                text.Add(str);

            foreach (string line in text)
            {
                if (line.StartsWith("[") && line.EndsWith("]"))
                    if (line.Contains(Section))
                        return true;
            }
            return false;
        }

        ///////////////////////////////////////////////////////////////////////////////////////
        //  Function:   Format
        //
        //  Params:     
        //
        //  Notes:      Going to format the INI file with empty lines between each section.
        //              Will not add empty lines before sections if an empty line already
        //              exists.
        ///////////////////////////////////////////////////////////////////////////////////////
        public void Format( )
        {
            string newline = Environment.NewLine;
            string fileName = Path; //"test.txt";
            List<string> txtLines = new List<string>();

            //Fill a List<string> with the lines from the txt file.
            foreach (string str in File.ReadAllLines(fileName))
                txtLines.Add(str);

            //Insert the line you want to add last under the tag 'item1'.
            List<string> newLines = new List<string>();
            foreach(string temp in txtLines)
            {
                if (temp.StartsWith("[") && temp.EndsWith("]") && txtLines.IndexOf(temp) > 0)
                    newLines.Add(newline + temp);
                else if (temp != "")
                    newLines.Add(temp);
            }

            //Clear the file. The using block will close the connection immediately.
            using (File.Create(fileName)) { }

            //Add the lines including the new one.
            foreach (string str in newLines)
                File.AppendAllText(fileName, str + Environment.NewLine);
        }
    }
}
